<template>
  <div class="p-6 bg-white rounded-lg shadow-lg">
    <h3 class="text-xl font-bold mb-4 text-gray-800">Vue nextTick 演示</h3>
    <div class="space-y-4">
      <div class="flex flex-wrap gap-2">
        <button
          @click="runNextTickDemo"
          class="px-4 py-2 bg-purple-500 text-white rounded hover:bg-purple-600 transition-colors"
        >
          运行 nextTick 演示
        </button>
        <button
          @click="runDomUpdateDemo"
          class="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 transition-colors"
        >
          DOM 更新演示
        </button>
        <button
          @click="clearLogs"
          class="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600 transition-colors"
        >
          清空日志
        </button>
      </div>

      <!-- 演示用的 DOM 元素 -->
      <div class="bg-gray-50 p-4 rounded-lg">
        <h4 class="font-semibold mb-2">演示元素：</h4>
        <div
          ref="demoElement"
          :style="{
            backgroundColor: elementColor,
            height: elementHeight + 'px',
            minHeight: elementHeight + 'px',
          }"
          class="demo-element"
        >
          <p class="text-white font-bold">{{ elementText }}</p>
          <p class="text-sm text-gray-200">设定高度: {{ elementHeight }}px</p>
          <p class="text-xs text-gray-300">实际高度: {{ actualHeight }}px</p>
        </div>
      </div>

      <div class="bg-gray-100 p-4 rounded-lg">
        <h4 class="font-semibold mb-2">执行日志：</h4>
        <div class="execution-log">
          <div
            v-for="(log, index) in logs"
            :key="index"
            :class="getLogClass(log.type)"
            class="py-1 px-2 mb-1 rounded"
          >
            <span class="font-mono text-sm">{{ log.message }}</span>
            <span class="text-xs opacity-75 ml-2">({{ log.type }})</span>
          </div>
        </div>
      </div>

      <div class="bg-purple-50 p-4 rounded-lg">
        <h4 class="font-semibold mb-2">nextTick 原理说明：</h4>
        <ul class="text-sm space-y-2">
          <li>• <strong>DOM 更新是异步的：</strong> Vue 会在下一个 tick 批量更新 DOM</li>
          <li>• <strong>nextTick 时机：</strong> 在 DOM 更新后、浏览器渲染前执行</li>
          <li>
            • <strong>获取更新后的 DOM：</strong> 在 nextTick 回调中可以获取到更新后的 DOM 状态
          </li>
          <li>
            • <strong>与微任务的关系：</strong> nextTick 本质上是微任务（Promise 或
            MutationObserver）
          </li>
          <li>
            • <strong>批量更新机制：</strong> 多次修改响应式数据会被批量处理，只触发一次 DOM 更新
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, nextTick } from 'vue'

interface LogEntry {
  message: string
  type: 'sync' | 'microtask' | 'macrotask' | 'nexttick' | 'dom'
  timestamp: number
}

const logs = ref<LogEntry[]>([])
const demoElement = ref<HTMLElement>()
const elementText = ref('初始文本')
const elementColor = ref('#3b82f6')
const elementHeight = ref(100)
const actualHeight = ref(100)

const addLog = (message: string, type: LogEntry['type']) => {
  logs.value.push({
    message,
    type,
    timestamp: Date.now(),
  })
}

const getLogClass = (type: string) => {
  const classes = {
    sync: 'bg-green-100 border-l-4 border-green-500',
    microtask: 'bg-yellow-100 border-l-4 border-yellow-500',
    macrotask: 'bg-red-100 border-l-4 border-red-500',
    nexttick: 'bg-purple-100 border-l-4 border-purple-500',
    dom: 'bg-blue-100 border-l-4 border-blue-500',
  }
  return classes[type as keyof typeof classes] || ''
}

const clearLogs = () => {
  logs.value = []
  elementText.value = '初始文本'
  elementColor.value = '#3b82f6'
  elementHeight.value = 100
  actualHeight.value = 100
}

const runNextTickDemo = async () => {
  clearLogs()

  addLog('1. 开始执行 nextTick 演示', 'sync')

  // 修改响应式数据
  elementText.value = '文本已更新'
  elementColor.value = '#ef4444'
  addLog('2. 修改了响应式数据', 'sync')

  // 立即检查 DOM（此时 DOM 还未更新）
  if (demoElement.value) {
    const currentText = demoElement.value.querySelector('p')?.textContent
    actualHeight.value = demoElement.value.offsetHeight
    addLog(`3. DOM 当前内容: "${currentText}"`, 'dom')
  }

  // 使用 nextTick
  nextTick(() => {
    addLog('4. nextTick 回调执行', 'nexttick')
    if (demoElement.value) {
      const updatedText = demoElement.value.querySelector('p')?.textContent
      actualHeight.value = demoElement.value.offsetHeight
      addLog(`5. DOM 更新后内容: "${updatedText}"`, 'dom')
    }
  })

  // 微任务
  Promise.resolve().then(() => {
    addLog('6. Promise.then 微任务执行', 'microtask')
  })

  // 宏任务
  setTimeout(() => {
    addLog('7. setTimeout 宏任务执行', 'macrotask')
  }, 0)

  addLog('8. 同步代码执行完毕', 'sync')
}

const runDomUpdateDemo = async () => {
  clearLogs()

  addLog('1. 开始 DOM 更新演示', 'sync')

  // 连续更新多次
  for (let i = 1; i <= 3; i++) {
    elementHeight.value = 100 + i * 20
    elementText.value = `第 ${i} 次更新`
    addLog(`2.${i} 设置高度为 ${100 + i * 20}px`, 'sync')
  }

  addLog('3. 所有同步更新完成', 'sync')

  // 立即检查 DOM 高度
  if (demoElement.value) {
    const currentHeight = demoElement.value.offsetHeight
    actualHeight.value = currentHeight
    addLog(`4. 当前 DOM 高度: ${currentHeight}px`, 'dom')
  }

  // nextTick 中检查
  await nextTick()
  if (demoElement.value) {
    const updatedHeight = demoElement.value.offsetHeight
    actualHeight.value = updatedHeight
    addLog(`5. nextTick 后 DOM 高度: ${updatedHeight}px`, 'nexttick')
  }

  // 演示批量更新的效果
  setTimeout(() => {
    elementColor.value = '#10b981'
    addLog('6. 宏任务中修改颜色', 'macrotask')

    nextTick(() => {
      if (demoElement.value) {
        actualHeight.value = demoElement.value.offsetHeight
      }
      addLog('7. 宏任务后的 nextTick', 'nexttick')
    })
  }, 100)
}
</script>

<style scoped lang="scss">
.demo-element {
  padding: 16px;
  border-radius: 8px;
  transition: all 0.3s ease;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;

  &:hover {
    transform: scale(1.02);
  }
}

.execution-log {
  max-height: 300px;
  overflow-y: auto;

  &::-webkit-scrollbar {
    width: 6px;
  }

  &::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 3px;
  }

  &::-webkit-scrollbar-thumb {
    background: #c1c1c1;
    border-radius: 3px;

    &:hover {
      background: #a8a8a8;
    }
  }
}
</style>
